/*
 * $Id: sysapi_path.c 98 2009-07-28 10:07:33Z hyunghwan.chung $
 *
   Copyright 2005-2009 Chung, Hyung-Hwan.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an  BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 */

#include <xp/bas/sysapi.h>
#include <xp/bas/locale.h>
#include <xp/bas/wstring.h>
#include <xp/bas/errno.h>
#include <stdio.h> /* for rename */

#if defined(_WIN32) && !defined(INVALID_FILE_ATTRIBUTES)
#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
#endif

#if defined(XP_USE_SYSCALL) && defined(XP_HAVE_SYS_SYSCALL_H)
#include <sys/syscall.h>
#endif

int xp_stat (const xp_char_t* path, xp_stat_t* buf)
{
#ifdef XP_CHAR_IS_MCHAR
	#if !defined(_LP64) && defined(SYS_stat64)
	return syscall (SYS_stat64, path, buf);
	#elif defined(SYS_stat)
	return syscall (SYS_stat, path, buf);
	#elif !defined(_LP64) && defined(HAVE_STAT64)
	return stat64 (path, buf);
	#else
	return stat (path, buf);
	#endif
#else
	xp_mchar_t path_mb[XP_PATH_MAX + 1];
	if (xp_wcstomcs_strict(path, path_mb, XP_COUNTOF(path_mb)) == -1) {
		return -1;
	}
	#if !defined(_LP64) && defined(SYS_stat64)
	return syscall (SYS_stat64, path_mb, buf);
	#elif defined(SYS_stat)
	return syscall (SYS_stat, path_mb, buf);
	#elif !defined(_LP64) && defined(HAVE_STAT64)
	return stat64 (path_mb, buf);
	#else
	return stat (path_mb, buf);
	#endif
#endif
}

int xp_unlink (const xp_char_t* path)
{
#ifdef _WIN32
	if (DeleteFile(path) == 0) {
		xp_seterrno (xp_maperrno(GetLastError()));
		return -1;
	}
	return 0;
#else

#ifdef XP_CHAR_IS_MCHAR
	#ifdef SYS_unlink
	return syscall (SYS_unlink, path);
	#else
	return unlink (path);
	#endif
#else
	xp_mchar_t path_mb[XP_PATH_MAX + 1];
	if (xp_wcstomcs_strict(path, path_mb, XP_COUNTOF(path_mb)) == -1) {
		return -1;
	}
	#ifdef SYS_unlink
	return syscall (SYS_unlink, path_mb);
	#else
	return unlink (path_mb);
	#endif
#endif

#endif
}

int xp_rename (const xp_char_t* opath, const xp_char_t* npath)
{
#ifdef _WIN32
	if (MoveFile(opath, npath) == 0) {
		xp_seterrno (xp_maperrno(GetLastError()));
		return -1;
	}
	return 0;
#else

#ifdef XP_CHAR_IS_MCHAR
	#ifdef SYS_rename
	return syscall (SYS_rename, opath, npath);
	#else
	return rename (opath, npath);
	#endif
#else
	xp_mchar_t opath_mb[XP_PATH_MAX + 1];
	xp_mchar_t npath_mb[XP_PATH_MAX + 1];
	if (xp_wcstomcs_strict(opath, opath_mb, XP_COUNTOF(opath_mb)) == -1) {
		return -1;
	}
	if (xp_wcstomcs_strict(npath, npath_mb, XP_COUNTOF(npath_mb)) == -1) {
		return -1;
	}
	#ifdef SYS_rename
	return syscall (SYS_rename, opath_mb, npath_mb);
	#else
	return rename (opath_mb, npath_mb);
	#endif
#endif

#endif
}

int xp_access (const xp_char_t* path, int option)
{
#ifdef _WIN32
	DWORD attr = GetFileAttributes (path);
	if (attr == INVALID_FILE_ATTRIBUTES) {
		xp_seterrno (xp_maperrno(GetLastError()));
		return -1;
	}

	if ((attr & FILE_ATTRIBUTE_READONLY) && (option & XP_ACCESS_WRITE)) {
		xp_seterrno (XP_EACCES);
		return -1;
	}

	return 0;

#else

#ifdef XP_CHAR_IS_MCHAR
	#ifdef SYS_access
	return syscall (SYS_access, path, option);
	#else
	return access (path, option);
	#endif
#else
	xp_mchar_t path_mb[XP_PATH_MAX + 1];
	if (xp_wcstomcs_strict(path, path_mb, XP_COUNTOF(path_mb)) == -1) {
		return -1;
	}
	#ifdef SYS_access
	return syscall (SYS_access, path_mb, option);
	#else
	return access (path_mb, option);
	#endif
#endif

#endif
}

int xp_chmod (const xp_char_t* path, xp_mode_t mode)
{
#ifdef _WIN32
	DWORD attr = GetFileAttributes (path);
	if (attr == INVALID_FILE_ATTRIBUTES) {
		xp_seterrno (xp_maperrno(GetLastError()));
		return -1;
	}

	if (mode & S_IWRITE) { /* TODO: replay S_IWRITE by xpkit's own definition */
		attr &= ~FILE_ATTRIBUTE_READONLY;
	}
	else {
		attr |= FILE_ATTRIBUTE_READONLY;
	}

	if (SetFileAttributes(path, attr) == 0) {
		xp_seterrno (xp_maperrno(GetLastError()));
		return -1;
	}

	return 0;
#else

#ifdef XP_CHAR_IS_MCHAR
	#ifdef SYS_chmod
	return syscall (SYS_chmod, path, mode);
	#else
	return chmod (path, mode);
	#endif
#else
	xp_mchar_t path_mb[XP_PATH_MAX + 1];
	if (xp_wcstomcs_strict(path, path_mb, XP_COUNTOF(path_mb)) == -1) {
		return -1;
	}
	#ifdef SYS_chmod
	return syscall (SYS_chmod, path_mb, mode);
	#else
	return chmod (path_mb, mode);
	#endif
#endif

#endif
}

int xp_chroot (const xp_char_t* path)
{
#ifdef _WIN32
	/* not supported */
	xp_seterrno (XP_ENOTSUP);
	return -1;
#else

#ifdef XP_CHAR_IS_MCHAR
	#ifdef SYS_chroot
	return syscall (SYS_chroot, path);
	#else
	return chroot (path);
	#endif
#else
	xp_mchar_t path_mb[XP_PATH_MAX + 1];
	if (xp_wcstomcs_strict(path, path_mb, XP_COUNTOF(path_mb)) == -1) 
	{
		return -1;
	}
	#ifdef SYS_chroot
	return syscall (SYS_chroot, path_mb);
	#else
	return chroot (path_mb);
	#endif
#endif

#endif
}
